//**********************************************************************************************************
//
//! \file DrvRTC.c
//! \brief This file provides all the RTC firmware functions.
//! \version V1.06
//! \date 14. March 2011
//! \author NuMicro MCU Software Team
//! \copy
//!
//! Copyright (c)  2011, Nuvoton Technology Corp.
//! All rights reserved.
//
//********************************************************************************************************** 

//**********************************************************************************************************
//
//!  Includes of local headers	
//							                                                   
//**********************************************************************************************************
#include <stdio.h>
#include "NANO1xx.h"
#include "DrvRTC.h"
#include "Assert.h"

//**********************************************************************************************************
//
//!  Macro, type and constant definitions
//  								                                                   
//**********************************************************************************************************
#define RTC_GLOBALS

#ifdef RTC_DEBUG
#define RTCDEBUG     printf
#else
#define RTCDEBUG(...)
#endif

//**********************************************************************************************************
//
//!  Global file scope (static) variables 
//  								                                                   
//**********************************************************************************************************
static PFN_DRVRTC_CALLBACK  *g_pfnRTCCallBack_Tick    = NULL, *g_pfnRTCCallBack_Alarm   = NULL, *g_pfnRTCCallBack_Snooper   = NULL;
                   
static volatile uint32_t g_u32RTC_Count  = 0;
static char g_chHourMode = 0;
static volatile int32_t g_bIsEnableTickInt  = NULL;
static volatile int8_t g_bIsEnableAlarmInt  = NULL;
static volatile int8_t g_bIsEnableSnooperInt  = NULL;

static volatile uint32_t g_u32Reg, g_u32Reg1,g_u32hiYear,g_u32loYear,g_u32hiMonth,g_u32loMonth,g_u32hiDay,g_u32loDay;
static volatile uint32_t g_u32hiHour,g_u32loHour,g_u32hiMin,g_u32loMin,g_u32hiSec,g_u32loSec;

//**********************************************************************************************************
//
//! \brief  RTC ISR to handle interrupt event.
//!
//! \param  None.
//!
//! \retval None.
//
//**********************************************************************************************************
void RTC_IRQHandler(void)
{ 
   
	if ( (RTC->RIER_BITS.TIER) && (RTC->RIIR_BITS.TIS==0x1) )		/* tick interrupt occurred */
	{
 		  RTC->RIIR = 0x2;
		  
		  g_u32RTC_Count++;                                            /* maintain RTC tick count */

          if (g_pfnRTCCallBack_Tick != NULL)                           /* execute tick callback function */
          {
              g_pfnRTCCallBack_Tick();
          }

    }

 	if ( (RTC->RIER_BITS.AIER) && (RTC->RIIR_BITS.AIS==0x1) )		/* alarm interrupt occurred */
    {          
		  RTC->RIIR = 0x1;
		  
		  if (g_pfnRTCCallBack_Alarm != NULL) 	                       /* execute alarm callback function */
          {
              g_pfnRTCCallBack_Alarm();
          }
    }

	if ( (RTC->RIER_BITS.SNOOPIER) && (RTC->RIIR_BITS.SNOOPIS==0x1) )	/* snooper interrupt occurred */
    {          
		  RTC->RIIR = 0x4;
		  
		  if (g_pfnRTCCallBack_Snooper != NULL) 	                       /* execute alarm callback function */
          {
              g_pfnRTCCallBack_Snooper();
          }
    }
}

 
//**********************************************************************************************************
//
//! \brief  Set Frequecy Compenation Data.
//!
//! \param  i32FrequencyX100 The RTC osillator clock X100, ex:3277365 means 32773.65 
//!
//! \retval E_SUCCESS				Success.                                                       
//!         ERR_RTC_FCR_VALUE		Wrong Compenation VALUE 
//
//**********************************************************************************************************
int32_t DrvRTC_SetFrequencyCompensation(int32_t i32FrequencyX100)
{
    int32_t i32RegInt,i32RegFra ;

	/* Compute Interger and Fraction for RTC register*/
    i32RegInt = (i32FrequencyX100/100) - DRVRTC_FCR_REFERENCE;
    i32RegFra = (((i32FrequencyX100%100)) * 60) / 100;
    
	/* Judge Interger part is reasonable */
    if ( (i32RegInt < 0) | (i32RegInt > 15) )
    {
        return E_DRVRTC_ERR_FCR_VALUE ;
    }
	
	DrvRTC_WriteEnable();

	RTC->FCR = (uint32_t)((i32RegInt<<8) | i32RegFra);

    return E_SUCCESS;
}

//**********************************************************************************************************
//
//! \brief  Access Password to AER to make access other register enable.
//!
//! \param  None 
//!
//! \retval E_SUCCESS		            Success                                                       
//!         E_DRVRTC_ERR_FAILED       	FAILED
//
//**********************************************************************************************************
int32_t DrvRTC_WriteEnable (void)
{
    int32_t i32i = 0;

	int i32retry = 100;
    
	/*-------------------------------------------------------------------------------------------------*/
    /* After 200ms, Access enable wiil auto-clear. As soon as possible to do your setting              */
    /*-------------------------------------------------------------------------------------------------*/
	RETRY:

	i32i = 0;
	
	RTC->AER_BITS.AER = DRVRTC_WRITE_KEY;
	
    for (i32i = 0 ; i32i < DRVRTC_WAIT_COUNT ; i32i++)
	{
        /*-------------------------------------------------------------------------------------------------*/
        /* check RTC_AER[16] to find out RTC write enable                                                  */
        /*-------------------------------------------------------------------------------------------------*/
 		RTC->AER_BITS.AER = DRVRTC_WRITE_KEY;
		
		if (RTC->AER_BITS.ENF ==1)	
		    break;
	}

	
	if (i32i == DRVRTC_WAIT_COUNT)
    {
        RTCDEBUG ("\nRTC: DrvRTC_WriteEnable, set write enable FAILED!\n");

		i32retry--;

        if(!i32retry)
	   		return E_DRVRTC_ERR_FAILED;
						
		goto RETRY;
    }

    
	return E_SUCCESS;
}

//**********************************************************************************************************
//
//! \brief  Initial RTC. It consists of clear callback function pointer, enable 32K clock and         
//!        RTC clock and write initial key to let RTC start count.
//!
//! \param  None 
//!
//! \retval E_SUCCESS		            Success                                                       
//!         E_DRVRTC_ERR_EIO			Initial RTC FAILED
//
//**********************************************************************************************************
int32_t DrvRTC_Init (void)
{
    int32_t i32i =0;
	
	volatile int32_t i32delay=1000;

    /*-----------------------------------------------------------------------------------------------------*/
    /* Initial time data struct and some parameters.                                                       */
    /*-----------------------------------------------------------------------------------------------------*/
    g_pfnRTCCallBack_Alarm = NULL;
    g_pfnRTCCallBack_Tick = NULL;
	g_pfnRTCCallBack_Snooper = NULL;

    g_u32RTC_Count = 0;

	/* un-lock */
	UNLOCKREG();
	/* Enable 32K Clock */
	CLK->PWRCTL_BITS.LXT_EN =1;
	  
	/* Waiting for 32K stable */
  	while(i32delay--);
	
	/* Enable RTC Clock */
	CLK->APBCLK_BITS.RTC_EN =1;
	
	LOCKREG();

    /*-----------------------------------------------------------------------------------------------------*/
    /* When RTC is power on, write 0xa5eb1357 to RTC_INIR to reset all logic.                              */
    /*-----------------------------------------------------------------------------------------------------*/
	
	RTC->INIR = DRVRTC_INIT_KEY;

    for (i32i = 0 ; i32i < DRVRTC_WAIT_COUNT ; i32i++)
    {

		if(RTC->INIR == 0x1)  /* Check RTC_INIR[0] to find out RTC reset signal */
        { 
            break;
        }
    }

    if (i32i == DRVRTC_WAIT_COUNT)
    {
        RTCDEBUG("\nRTC: DrvRTC_Init, initial RTC FAILED!\n");
        return E_DRVRTC_ERR_EIO;
    }

    return E_SUCCESS;
}

//**********************************************************************************************************
//
//! \brief  Set Current time (Year/Month/Day, Hour/Minute/Sec and day of week).
//!
//! \param  sPt		Just Set Current_Timer
//!
//! \retval E_SUCCESS		    Success                                                       
//!         Error Code			Accodring to stuation to report error code
//
//**********************************************************************************************************
int32_t DrvRTC_Open (S_DRVRTC_TIME_DATA_T *sPt)
{
    uint32_t u32Reg;
	
	volatile int32_t i32delay=1000;
        
    /*-----------------------------------------------------------------------------------------------------*/
    /* DO BASIC JUDGEMENT TO Check RTC time data value is reasonable or not.                               */
    /*-----------------------------------------------------------------------------------------------------*/
	assert_param(	!( ((sPt->u32Year - DRVRTC_YEAR2000) > 99)|
							((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12))|
							((sPt->u32cDay   == 0) || (sPt->u32cDay   > 31))));

	assert_param( (sPt->u8cClockDisplay==DRVRTC_CLOCK_12) || (sPt->u8cClockDisplay==DRVRTC_CLOCK_24));

	assert_param(	!( (sPt->u8cClockDisplay==DRVRTC_CLOCK_12) &&
							((sPt->u32cHour == 0) || (sPt->u32cHour > 12))));

	assert_param(	!( (sPt->u8cClockDisplay==DRVRTC_CLOCK_24) &&
							(sPt->u32cHour > 23)));

	assert_param(	!((sPt->u32cMinute > 59) |
							(sPt->u32cSecond > 59) |
							(sPt->u32cSecond > 59)));

	assert_param( !(sPt->u32cDayOfWeek > 6) );


    /*-----------------------------------------------------------------------------------------------------*/
    /* Important, call DrvRTC_WriteEnable() before write data into any register.                              */
    /* User should be write data as soon as possible.Access enable wiil clear after 200ms                  */
	/*-----------------------------------------------------------------------------------------------------*/
    g_u32Reg = DrvRTC_WriteEnable();
    if (g_u32Reg != 0)
    {
        return E_DRVRTC_ERR_FAILED;
    }
    
    /*-----------------------------------------------------------------------------------------------------*/
    /* Second, set RTC 24/12 hour setting                                                                  */
    /*-----------------------------------------------------------------------------------------------------*/
    if (sPt->u8cClockDisplay == DRVRTC_CLOCK_12)
    {
        DrvRTC_WriteEnable();
 		RTC->TSSR_BITS.HR24 = DRVRTC_CLOCK_12;

        /*-------------------------------------------------------------------------------------------------*/
        /* important, range of 12-hour PM mode is 21 upto 32                                               */
        /*-------------------------------------------------------------------------------------------------*/
        if (sPt->u8cAmPm == DRVRTC_PM)
            sPt->u32cHour += 20;
    }
    else                                                                               /* DRVRTC_CLOCK_24 */
    {

        DrvRTC_WriteEnable();
 		RTC->TSSR_BITS.HR24 = DRVRTC_CLOCK_24;
        RTCDEBUG ("RTC: 24-hour\n");
    }

    /*-----------------------------------------------------------------------------------------------------*/
    /* Set RTC Calender Loading                                                                            */
    /*-----------------------------------------------------------------------------------------------------*/
    u32Reg    = ((sPt->u32Year - DRVRTC_YEAR2000) / 10) << 20;
    u32Reg    |= (((sPt->u32Year - DRVRTC_YEAR2000) % 10) << 16);
    u32Reg    |= ((sPt->u32cMonth  / 10) << 12);
    u32Reg    |= ((sPt->u32cMonth  % 10) << 8);
    u32Reg    |= ((sPt->u32cDay    / 10) << 4);
    u32Reg    |= (sPt->u32cDay     % 10);
    g_u32Reg = u32Reg;
	
	DrvRTC_WriteEnable();
 	RTC->TSSR_BITS.HR24 = DRVRTC_CLOCK_24;
    RTC->CLR = (uint32_t)g_u32Reg;

	/*-----------------------------------------------------------------------------------------------------*/
    /* Set RTC Time Loading                                                                                */
    /*-----------------------------------------------------------------------------------------------------*/
    u32Reg     = ((sPt->u32cHour / 10) << 20);
    u32Reg    |= ((sPt->u32cHour % 10) << 16);
    u32Reg    |= ((sPt->u32cMinute / 10) << 12);
    u32Reg    |= ((sPt->u32cMinute % 10) << 8);
    u32Reg    |= ((sPt->u32cSecond / 10) << 4);
    u32Reg    |= (sPt->u32cSecond % 10);
    g_u32Reg = u32Reg;

 	DrvRTC_WriteEnable();
    RTC->TLR = (uint32_t)g_u32Reg;

	RTC->DWR = sPt->u32cDayOfWeek;

	RTC->TTR_BITS.TWKE = sPt->u8IsEnableWakeUp;

	/* Waiting for RTC settings stable */
  	while(i32delay--);

    return E_SUCCESS;
}

//**********************************************************************************************************
//
//! \brief  Read current date/time or alarm date/time from RTC setting.
//!
//! \param  eTime		Currnet_Timer/ Alarm_Time
//! \param  spt			Time Data  
//!
//! \retval E_SUCCESS		            Success                                                       
//!         E_DRVRTC_ERR_ENOTTY		Parameter is wrong
//
//********************************************************************************************************** 
int32_t DrvRTC_Read (E_DRVRTC_TIME_SELECT eTime, S_DRVRTC_TIME_DATA_T *sPt)
{
    uint32_t u32Tmp;
    
    sPt->u8cClockDisplay = RTC->TSSR_BITS.HR24;                                 /* 12/24-hour */
    sPt->u32cDayOfWeek   = RTC->DWR_BITS.DWR;                                   /* Day of week */

    switch (eTime)
    {
        case DRVRTC_CURRENT_TIME:										   /* Get Current Time */
        {
			g_u32hiYear  = RTC->CLR_BITS.TEN_YEAR;
    		g_u32loYear  = RTC->CLR_BITS.YEAR;
    		g_u32hiMonth = RTC->CLR_BITS.TEN_MON;
    		g_u32loMonth = RTC->CLR_BITS.MON;
    		g_u32hiDay   = RTC->CLR_BITS.TEN_DAY;
    		g_u32loDay   = RTC->CLR_BITS.DAY;

		    g_u32hiHour =  RTC->TLR_BITS.TEN_HR;
    		g_u32loHour =  RTC->TLR_BITS.HR;
    		g_u32hiMin  =  RTC->TLR_BITS.TEN_MIN;
    		g_u32loMin  =  RTC->TLR_BITS.MIN;
    		g_u32hiSec  =  RTC->TLR_BITS.TEN_SEC;
    		g_u32loSec  =  RTC->TLR_BITS.SEC;
            break;
		}
        case DRVRTC_ALARM_TIME:									 	/* Get Alarm Time */
        {
			g_u32hiYear  = RTC->CAR_BITS.TEN_YEAR;
    		g_u32loYear  = RTC->CAR_BITS.YEAR;
    		g_u32hiMonth = RTC->CAR_BITS.TEN_MON;
    		g_u32loMonth = RTC->CAR_BITS.MON;
    		g_u32hiDay   = RTC->CAR_BITS.TEN_DAY;
    		g_u32loDay   = RTC->CAR_BITS.DAY;

		    g_u32hiHour =  RTC->TAR_BITS.TEN_HR;
    		g_u32loHour =  RTC->TAR_BITS.HR;
    		g_u32hiMin  =  RTC->TAR_BITS.TEN_MIN;
    		g_u32loMin  =  RTC->TAR_BITS.MIN;
    		g_u32hiSec  =  RTC->TAR_BITS.TEN_SEC;
    		g_u32loSec  =  RTC->TAR_BITS.SEC;
            break;
        }
        default:
        {
            return E_DRVRTC_ERR_ENOTTY;
        }
    }

    u32Tmp = (g_u32hiYear * 10);									/* Compute to 20XX year */
    u32Tmp+= g_u32loYear;
    sPt->u32Year   =   u32Tmp  + DRVRTC_YEAR2000;
    
    u32Tmp = (g_u32hiMonth * 10);									/* Compute 0~12 month */
    sPt->u32cMonth = u32Tmp + g_u32loMonth;
    
    u32Tmp = (g_u32hiDay * 10);										/* Compute 0~31 day */
    sPt->u32cDay   =  u32Tmp  + g_u32loDay;

    if (sPt->u8cClockDisplay == DRVRTC_CLOCK_12)					/* Compute12/24 hout */
    {
        u32Tmp = (g_u32hiHour * 10);
        u32Tmp+= g_u32loHour;
        sPt->u32cHour = u32Tmp;                                		/* AM: 1~12. PM: 21~32. */

        if (sPt->u32cHour >= 21)
        {
            sPt->u8cAmPm = DRVRTC_PM;
            sPt->u32cHour -= 20;
        }
        else
        {
            sPt->u8cAmPm = DRVRTC_AM;
        }
        
        u32Tmp = (g_u32hiMin  * 10);
        u32Tmp+= g_u32loMin;
        sPt->u32cMinute = u32Tmp;
        
        u32Tmp = (g_u32hiSec  * 10);
        u32Tmp+= g_u32loSec;
        sPt->u32cSecond = u32Tmp;

    }
    else
    {   															/* DRVRTC_CLOCK_24 */
        u32Tmp = (g_u32hiHour * 10);
        u32Tmp+= g_u32loHour;
        sPt->u32cHour   = u32Tmp;
        
        u32Tmp = (g_u32hiMin  * 10);
        u32Tmp+= g_u32loMin;
        sPt->u32cMinute = u32Tmp;
        
        u32Tmp = (g_u32hiSec  * 10);
        u32Tmp+= g_u32loSec;
        sPt->u32cSecond = u32Tmp;
    }

    return E_SUCCESS;

}

//**********************************************************************************************************
//
//! \brief  Access Password to AER to make access other register enable.
//!
//! \param  None 
//!
//! \retval E_SUCCESS		        Success                                                       
//!         E_DRVRTC_ERR_ENOTTY		Parameter is wrong
//!         E_DRVRTC_ERR_FAILED 	Initial RTC FAILED
//
//**********************************************************************************************************
int32_t DrvRTC_Write(E_DRVRTC_TIME_SELECT eTime, S_DRVRTC_TIME_DATA_T *sPt)
{
    uint32_t u32Reg;
    /*-----------------------------------------------------------------------------------------------------*/
    /* Check RTC time data value is reasonable or not.                                                     */
    /*-----------------------------------------------------------------------------------------------------*/
	assert_param(	!( ((sPt->u32Year - DRVRTC_YEAR2000) > 99)|
							((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12))|
							((sPt->u32cDay   == 0) || (sPt->u32cDay   > 31))));

	assert_param( !( (sPt->u32cMonth == 0) || (sPt->u32cMonth > 12) ));
    
	assert_param( !( (sPt->u32cDay == 0) || (sPt->u32cDay > 31) ));

	assert_param( (sPt->u8cClockDisplay==DRVRTC_CLOCK_12) || (sPt->u8cClockDisplay==DRVRTC_CLOCK_24));

	assert_param(	!( (sPt->u8cClockDisplay==DRVRTC_CLOCK_12) &&
							((sPt->u32cHour == 0) || (sPt->u32cHour > 12))));

	assert_param(	!( (sPt->u8cClockDisplay==DRVRTC_CLOCK_24) &&
							(sPt->u32cHour > 23)));

	assert_param( !(sPt->u32cMinute > 59));
	assert_param( !(sPt->u32cSecond > 59));
	assert_param( !(sPt->u32cDayOfWeek > 6));


    /*-----------------------------------------------------------------------------------------------------*/
    /* Important, call DrvRTC_Open() before write data into any register.                                     */
    /*-----------------------------------------------------------------------------------------------------*/
    g_u32Reg = DrvRTC_WriteEnable();
    if (g_u32Reg != 0)
    {
        return E_DRVRTC_ERR_FAILED;
    }

    switch (eTime)
    {

        case DRVRTC_CURRENT_TIME:
            /*---------------------------------------------------------------------------------------------*/
            /* Second, set RTC time data.                                                                  */
            /*---------------------------------------------------------------------------------------------*/

            if (sPt->u8cClockDisplay == DRVRTC_CLOCK_12)
            {
                g_chHourMode = DRVRTC_CLOCK_12;
				RTC->TSSR_BITS.HR24 = DRVRTC_CLOCK_12;
                RTCDEBUG ("RTC: 12-hour\n");
                /*-----------------------------------------------------------------------------------------*/
                /* important, range of 12-hour PM mode is 21 upto 32                                       */
                /*-----------------------------------------------------------------------------------------*/
                if (sPt->u8cAmPm == DRVRTC_PM)
                    sPt->u32cHour += 20;
            }
            else                                                                  /* DRVRTC_CLOCK_24 */
            {
                g_chHourMode = DRVRTC_CLOCK_24;
    			RTC->TSSR_BITS.HR24 = DRVRTC_CLOCK_24;
                RTCDEBUG ("RTC: 24-hour\n");
            }

  			RTC->DWR_BITS.DWR = sPt->u32cDayOfWeek;

		    
			/*---------------------------------------------------------------------------------------------*/
            /* Second, set RTC time data.                                                                  */
            /*---------------------------------------------------------------------------------------------*/

			u32Reg     = ((sPt->u32Year - DRVRTC_YEAR2000) / 10) << 20;
		    u32Reg    |= (((sPt->u32Year - DRVRTC_YEAR2000) % 10) << 16);
		    u32Reg    |= ((sPt->u32cMonth  / 10) << 12);
		    u32Reg    |= ((sPt->u32cMonth  % 10) << 8);
		    u32Reg    |= ((sPt->u32cDay    / 10) << 4);
		    u32Reg    |= (sPt->u32cDay     % 10);
            g_u32Reg = u32Reg;
			DrvRTC_WriteEnable();
          
			RTC->CLR = (uint32_t)g_u32Reg;
			RTCDEBUG ("RTC: REG_RTC_CLR[0x%08x]\n", RTC->CLR);  
            
		    u32Reg     = ((sPt->u32cHour / 10) << 20);
		    u32Reg    |= ((sPt->u32cHour % 10) << 16);
		    u32Reg    |= ((sPt->u32cMinute / 10) << 12);
		    u32Reg    |= ((sPt->u32cMinute % 10) << 8);
		    u32Reg    |= ((sPt->u32cSecond / 10) << 4);
		    u32Reg    |= (sPt->u32cSecond % 10);
			g_u32Reg = u32Reg;
		
			DrvRTC_WriteEnable();
           	RTC->TLR = (uint32_t)g_u32Reg;
			RTCDEBUG ("RTC: REG_RTC_TLR[0x%08x]\n", RTC->TLR);   
			
            return E_SUCCESS;


         case DRVRTC_ALARM_TIME:

            g_pfnRTCCallBack_Alarm = NULL;                                /* Initial call back function.*/
            
			/*---------------------------------------------------------------------------------------------*/
            /* Set Calender alarm time data.                                                               */
            /*---------------------------------------------------------------------------------------------*/
		    u32Reg     = ((sPt->u32Year - DRVRTC_YEAR2000) / 10) << 20;
		    u32Reg    |= (((sPt->u32Year - DRVRTC_YEAR2000) % 10) << 16);
		    u32Reg    |= ((sPt->u32cMonth  / 10) << 12);
		    u32Reg    |= ((sPt->u32cMonth  % 10) << 8);
		    u32Reg    |= ((sPt->u32cDay    / 10) << 4);
		    u32Reg    |= (sPt->u32cDay     % 10);
            g_u32Reg = u32Reg;
			DrvRTC_WriteEnable();
			
			RTC->CAR = (uint32_t)g_u32Reg;
			RTCDEBUG ("RTC: REG_RTC_CAR[0x%08x]\n", RTC->CAR);  
			
						 
            if (g_chHourMode == DRVRTC_CLOCK_12)
            {
                if (sPt->u8cAmPm == DRVRTC_PM)       /* important, range of 12-hour PM mode is 21 upto 32 */
                    sPt->u32cHour += 20;
            }

			/*---------------------------------------------------------------------------------------------*/
            /* Set Time alarm time data.                                                                   */
            /*---------------------------------------------------------------------------------------------*/
		    u32Reg     = ((sPt->u32cHour / 10) << 20);
		    u32Reg    |= ((sPt->u32cHour % 10) << 16);
		    u32Reg    |= ((sPt->u32cMinute / 10) << 12);
		    u32Reg    |= ((sPt->u32cMinute % 10) << 8);
		    u32Reg    |= ((sPt->u32cSecond / 10) << 4);
		    u32Reg    |= (sPt->u32cSecond % 10);

			g_u32Reg = u32Reg;
            DrvRTC_WriteEnable();
           	RTC->TAR = (uint32_t)g_u32Reg;
			RTCDEBUG ("RTC: REG_RTC_TAR[0x%08x]\n", RTC->TAR);   

			/*---------------------------------------------------------------------------------------------*/
            /* Finally, enable alarm interrupt.                                                            */
            /*---------------------------------------------------------------------------------------------*/
			DrvRTC_EnableInt(DRVRTC_ALARM_INT,NULL);
            
			RTC->TTR_BITS.TWKE = sPt->u8IsEnableWakeUp;
			return E_SUCCESS;


	        default:
	        {
	            return E_DRVRTC_ERR_ENOTTY;
	        }
    }

}

//**********************************************************************************************************
//
//! \brief  Read/Write the spare registers.
//!
//! \param  sparenum        Specify the number of register
//! \param  value			The value will be wrote
//! \param  wrsel			Specify the writing/reading access  [1:Write; 0:Read]
//!
//! \retval The content value of specified spare register                                                       
//
//**********************************************************************************************************
int32_t DrvRTC_SpareRegsAccess (int32_t sparenum, int32_t value, int32_t wrsel)
{
	uint32_t ret = E_SUCCESS;

	DrvRTC_WriteEnable();

	if(wrsel==0)
		while(RTC->SPRCTL_BITS.SPRRDY!=1) ;
	
	if(sparenum==0)
		(wrsel==1) ? (RTC->SPR0=value) : (ret=RTC->SPR0);
	if(sparenum==1)
		(wrsel==1) ? (RTC->SPR1=value) : (ret=RTC->SPR1);
	if(sparenum==2)
		(wrsel==1) ? (RTC->SPR2=value) : (ret=RTC->SPR2);
	if(sparenum==3)
		(wrsel==1) ? (RTC->SPR3=value) : (ret=RTC->SPR3);
	if(sparenum==4)
		(wrsel==1) ? (RTC->SPR4=value) : (ret=RTC->SPR4);
	if(sparenum==5)
		(wrsel==1) ? (RTC->SPR5=value) : (ret=RTC->SPR5);
	if(sparenum==6)
		(wrsel==1) ? (RTC->SPR6=value) : (ret=RTC->SPR6);
	if(sparenum==7)
		(wrsel==1) ? (RTC->SPR7=value) : (ret=RTC->SPR7);
	if(sparenum==8)
		(wrsel==1) ? (RTC->SPR8=value) : (ret=RTC->SPR8);
	if(sparenum==9)
		(wrsel==1) ? (RTC->SPR9=value) : (ret=RTC->SPR9);
	if(sparenum==10)
		(wrsel==1) ? (RTC->SPR10=value) : (ret=RTC->SPR10);
	if(sparenum==11)
		(wrsel==1) ? (RTC->SPR11=value) : (ret=RTC->SPR11);
	if(sparenum==12)
		(wrsel==1) ? (RTC->SPR12=value) : (ret=RTC->SPR12);
	if(sparenum==13)
		(wrsel==1) ? (RTC->SPR13=value) : (ret=RTC->SPR13);
	if(sparenum==14)
		(wrsel==1) ? (RTC->SPR14=value) : (ret=RTC->SPR14);
	if(sparenum==15)
		(wrsel==1) ? (RTC->SPR15=value) : (ret=RTC->SPR15);
	if(sparenum==16)
		(wrsel==1) ? (RTC->SPR16=value) : (ret=RTC->SPR16);
	if(sparenum==17)
		(wrsel==1) ? (RTC->SPR17=value) : (ret=RTC->SPR17);
	if(sparenum==18)
		(wrsel==1) ? (RTC->SPR18=value) : (ret=RTC->SPR18);
	if(sparenum==19)
		(wrsel==1) ? (RTC->SPR19=value) : (ret=RTC->SPR19);

	if(wrsel==1)
		while(RTC->SPRCTL_BITS.SPRRDY!=1) ;
	
	return ret;

}

//**********************************************************************************************************
//
//! \brief  Enable Spare function and set the detection edge.
//!
//! \param  eSpareEdge	Detection edge (DRVRTC_SNOOPER_RISING, DRVRTC_SNOOPER_FALLING)
//!
//! \retval None                                                       
//
//**********************************************************************************************************
void DrvRTC_EnableSpareFunc(E_DRVRTC_SNOOPER_EDGE eSpareEdge)
{
	DrvRTC_WriteEnable();

	/* detection edge select */
	RTC->SPRCTL_BITS.SNOOPEDGE = eSpareEdge;
	while(RTC->SPRCTL_BITS.SPRRDY!=1) ;
	
	/* enable snooper pin event detection */
	RTC->SPRCTL_BITS.SNOOPEN = 1;
	while(RTC->SPRCTL_BITS.SPRRDY!=1) ;
}

//**********************************************************************************************************
//
//! \brief  Disable Spare function.
//!
//! \param  None 
//!
//! \retval None                                                      
//
//**********************************************************************************************************
void DrvRTC_DisableSpareFunc(void)
{
	DrvRTC_WriteEnable();

	/* Disable snooper pin event detection */
	RTC->SPRCTL_BITS.SNOOPEN = 0;
	while(RTC->SPRCTL_BITS.SPRRDY!=1) ;
}

//**********************************************************************************************************
//
//! \brief  The function is used to get current Software tick count after enable tick interrupt.
//!
//! \param  None 
//!
//! \retval Software Tick Count in tick interrupt ex.If the RTC tick mode is 1 tick /sec. After 10 second , 
//! it should be return 10.                                                     
//
//**********************************************************************************************************
int32_t DrvRTC_GetIntTick(void)
{
	return g_u32RTC_Count;
}

//**********************************************************************************************************
//
//! \brief  The function is used to reset the tick count counting in interrupt.
//!
//! \param  None 
//!
//! \retval None		           
//
//**********************************************************************************************************
void DrvRTC_ResetIntTick(void)
{
	g_u32RTC_Count = 0;
}

//**********************************************************************************************************
//
//! \brief  According current time setting, return this is LEAP year or not.
//!
//! \param  None 
//!
//! \retval 1:  This year is LEAP year                                                        
//!         0:  This year is NOT LEAP year
//
//**********************************************************************************************************
int32_t DrvRTC_IsLeapYear(void)
{
	return (RTC->LIR_BITS.LIR == 0x1)?1:0;
}

//**********************************************************************************************************
//
//! \brief  The function is used to set time tick period for periodic time tick Interrupt.
//!
//! \param  unMode  The structure of E_DRVRTC_TICK. It is ued to set the RTC time tick period for Periodic 
//! Time Tick Interrupt request It consists of DRVRTC_TICK_1_SEC ~ DRVRTC_TICK_1_128_SEC 
//!
//! \retval E_SUCCESS		            Operation Successful                                                      
//!         E_DRVRTC_ERR_FAILED       	Access Enable failed 
//!         E_DRVRTC_ERR_ENOTTY    	    Parameter is wrong
//
//**********************************************************************************************************
int32_t DrvRTC_SetTickMode(uint8_t ucMode)
{
    g_u32RTC_Count = 0;
	
    if (DrvRTC_WriteEnable() != 0)   				/* Write PASSWORD to access enable*/
    {
    	return E_DRVRTC_ERR_EIO ;
    }
    
	if (ucMode > DRVRTC_TICK_1_128_SEC)             /* Tick mode 0 to 7 */
    {
    	return E_DRVRTC_ERR_ENOTTY ;
    }
            
  	RTC->TTR_BITS.TTR = ucMode;            

	return E_SUCCESS;

}

//**********************************************************************************************************
//
//! \brief  Access Password to AER to make access other register enable.
//!
//! \param   str_IntSrc		Interrupt Source:  DRVRTC_TICK_INT / DRVRTC_ALARM_INT / DRVRTC_SNOOPER_INT
//! \param   pfncallback	Callback function pointer 
//!
//! \retval E_SUCCESS		            Operation Successful                                                      
//!         E_DRVRTC_ERR_ENOTTY       	Wrong Parameter
//
//**********************************************************************************************************
int32_t DrvRTC_EnableInt(E_DRVRTC_INT_SOURCE str_IntSrc, PFN_DRVRTC_CALLBACK pfncallback)
{
	switch (str_IntSrc)
    {

    	case DRVRTC_TICK_INT:
        {
        	g_bIsEnableTickInt   	= true;
   			RTC->RIER_BITS.TIER 			= 1; 
			g_pfnRTCCallBack_Tick  	= pfncallback;
   			break;
        }
        case DRVRTC_ALARM_INT:
        {
            g_bIsEnableAlarmInt  	= true;
    		RTC->RIER_BITS.AIER 			= 1; 
			g_pfnRTCCallBack_Alarm 	= pfncallback;
            break;
        }
		case DRVRTC_SNOOPER_INT:
        {
            g_bIsEnableSnooperInt  	= true;
    		RTC->RIER_BITS.SNOOPIER 			= 1; 
			g_pfnRTCCallBack_Snooper 	= pfncallback;
            break;
        }
        default:
        {
            return E_DRVRTC_ERR_ENOTTY;
        }
    }
	NVIC_EnableIRQ(RTC_IRQn); 

	return E_SUCCESS;

}

//**********************************************************************************************************
//
//! \brief  This function is used to disable RTC specified interrupt and remove callback function.
//!
//! \param  i32IntSrc  Interrupt Source:  DRVRTC_TICK_INT / DRVRTC_ALARM_INT /DRVRTC_ALL_INT
//!
//! \retval E_SUCCESS      		Operation Successful                                                       
//!         ERR_RTC_ENOTTY    	Wrong Parameter
//
//**********************************************************************************************************
int32_t DrvRTC_DisableInt(E_DRVRTC_INT_SOURCE i32IntSrc)
{
	
	if((i32IntSrc & DRVRTC_TICK_INT) == DRVRTC_TICK_INT	)
	{
		g_bIsEnableTickInt  = false;	
		RTC->RIER_BITS.TIER 		= 0; 
		RTC->RIIR_BITS.TIS 		= 1; 
	}
	else if((i32IntSrc & DRVRTC_ALARM_INT) == DRVRTC_ALARM_INT )
	{
        g_bIsEnableAlarmInt = false;
    	RTC->RIER_BITS.AIER 		= 0; 
		RTC->RIIR_BITS.AIS 		= 1; 
	}
	else if((i32IntSrc & DRVRTC_SNOOPER_INT) == DRVRTC_SNOOPER_INT )
	{
        g_bIsEnableSnooperInt = false;
    	RTC->RIER_BITS.SNOOPIER 		= 0; 
		RTC->RIIR_BITS.SNOOPIS 		= 1; 
	}
	else
	{
		return E_DRVRTC_ERR_ENOTTY;
	}
	return E_SUCCESS;	

}

//**********************************************************************************************************
//
//! \brief  Disable NVIC channel of RTC and both tick and alarm interrupt.
//!
//! \param  None 
//!
//! \retval E_SUCCESS                Success                                                      
//
//**********************************************************************************************************
int32_t DrvRTC_Close (void)
{

    g_bIsEnableTickInt = false;
    g_bIsEnableAlarmInt = false;
    g_bIsEnableSnooperInt = false;
    
  	NVIC_DisableIRQ(RTC_IRQn);
  
  	DrvRTC_DisableInt(DRVRTC_ALL_INT);
	
    return E_SUCCESS;
}

//**********************************************************************************************************
//
//! \brief  This function is used to get the RTC version number.
//!
//! \param  None 
//!
//! \retval None                                                       
//
//**********************************************************************************************************
int32_t DrvRTC_GetVersion (void)
{
	return DRVRTC_VERSION_NUM;
}







